home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2010 April / PCA177.iso / ESSENTIALS / Firefox Setup.exe / nonlocalized / chrome / browser.jar / content / browser / aboutSessionRestore.js < prev    next >
Encoding:
JavaScript  |  2009-07-15  |  11.5 KB  |  333 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is the nsSessionStore component.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Simon B├╝nzli <zeniko@gmail.com>
  18.  * Portions created by the Initial Developer are Copyright (C) 2008
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *
  23.  * Alternatively, the contents of this file may be used under the terms of
  24.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  25.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.  * in which case the provisions of the GPL or the LGPL are applicable instead
  27.  * of those above. If you wish to allow use of your version of this file only
  28.  * under the terms of either the GPL or the LGPL, and not to allow others to
  29.  * use your version of this file under the terms of the MPL, indicate your
  30.  * decision by deleting the provisions above and replace them with the notice
  31.  * and other provisions required by the GPL or the LGPL. If you do not delete
  32.  * the provisions above, a recipient may use your version of this file under
  33.  * the terms of any one of the MPL, the GPL or the LGPL.
  34.  *
  35.  * ***** END LICENSE BLOCK ***** */
  36.  
  37. const Cc = Components.classes;
  38. const Ci = Components.interfaces;
  39.  
  40. var gStateObject;
  41. var gTreeData;
  42.  
  43. // Page initialization
  44.  
  45. window.onload = function() {
  46.   // the crashed session state is kept inside a textbox so that SessionStore picks it up
  47.   // (for when the tab is closed or the session crashes right again)
  48.   var sessionData = document.getElementById("sessionData");
  49.   if (!sessionData.value) {
  50.     var ss = Cc["@mozilla.org/browser/sessionstartup;1"].getService(Ci.nsISessionStartup);
  51.     sessionData.value = ss.state;
  52.     if (!sessionData.value) {
  53.       document.getElementById("errorTryAgain").disabled = true;
  54.       return;
  55.     }
  56.   }
  57.   // make sure the data is tracked to be restored in case of a subsequent crash
  58.   var event = document.createEvent("UIEvents");
  59.   event.initUIEvent("input", true, true, window, 0);
  60.   sessionData.dispatchEvent(event);
  61.   
  62.   var s = new Components.utils.Sandbox("about:blank");
  63.   gStateObject = Components.utils.evalInSandbox("(" + sessionData.value + ")", s);
  64.   
  65.   initTreeView();
  66.   
  67.   document.getElementById("errorTryAgain").focus();
  68. };
  69.  
  70. function initTreeView() {
  71.   var tabList = document.getElementById("tabList");
  72.   var winLabel = tabList.getAttribute("_window_label");
  73.   
  74.   gTreeData = [];
  75.   gStateObject.windows.forEach(function(aWinData, aIx) {
  76.     var winState = {
  77.       label: winLabel.replace("%S", (aIx + 1)),
  78.       open: true,
  79.       checked: true,
  80.       ix: aIx
  81.     };
  82.     winState.tabs = aWinData.tabs.map(function(aTabData) {
  83.       var entry = aTabData.entries[aTabData.index - 1] || { url: "about:blank" };
  84.       var iconURL = aTabData.attributes && aTabData.attributes.image || null;
  85.       // don't initiate a connection just to fetch a favicon (see bug 462863)
  86.       if (/^https?:/.test(iconURL))
  87.         iconURL = "moz-anno:favicon:" + iconURL;
  88.       return {
  89.         label: entry.title || entry.url,
  90.         checked: true,
  91.         src: iconURL,
  92.         parent: winState
  93.       };
  94.     });
  95.     gTreeData.push(winState);
  96.     for each (var tab in winState.tabs)
  97.       gTreeData.push(tab);
  98.   }, this);
  99.   
  100.   tabList.view = treeView;
  101.   tabList.view.selection.select(0);
  102. }
  103.  
  104. // User actions
  105.  
  106. function restoreSession() {
  107.   document.getElementById("errorTryAgain").disabled = true;
  108.   
  109.   // remove all unselected tabs from the state before restoring it
  110.   var ix = gStateObject.windows.length - 1;
  111.   for (var t = gTreeData.length - 1; t >= 0; t--) {
  112.     if (treeView.isContainer(t)) {
  113.       if (gTreeData[t].checked === 0)
  114.         // this window will be restored partially
  115.         gStateObject.windows[ix].tabs =
  116.           gStateObject.windows[ix].tabs.filter(function(aTabData, aIx)
  117.                                                  gTreeData[t].tabs[aIx].checked);
  118.       else if (!gTreeData[t].checked)
  119.         // this window won't be restored at all
  120.         gStateObject.windows.splice(ix, 1);
  121.       ix--;
  122.     }
  123.   }
  124.   var stateString = gStateObject.toSource();
  125.   
  126.   var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
  127.   var top = getBrowserWindow();
  128.   
  129.   // if there's only this page open, reuse the window for restoring the session
  130.   if (top.gBrowser.tabContainer.childNodes.length == 1) {
  131.     ss.setWindowState(top, stateString, true);
  132.     return;
  133.   }
  134.   
  135.   // restore the session into a new window and close the current tab
  136.   var newWindow = top.openDialog(top.location, "_blank", "chrome,dialog=no,all");
  137.   newWindow.addEventListener("load", function() {
  138.     newWindow.removeEventListener("load", arguments.callee, true);
  139.     ss.setWindowState(newWindow, stateString, true);
  140.     
  141.     var tabbrowser = top.gBrowser;
  142.     var tabIndex = tabbrowser.getBrowserIndexForDocument(document);
  143.     tabbrowser.removeTab(tabbrowser.tabContainer.childNodes[tabIndex]);
  144.   }, true);
  145. }
  146.  
  147. function startNewSession() {
  148.   getBrowserWindow().BrowserHome();
  149. }
  150.  
  151. function onListClick(aEvent) {
  152.   // don't react to right-clicks
  153.   if (aEvent.button == 2)
  154.     return;
  155.   
  156.   var row = {}, col = {};
  157.   treeView.treeBox.getCellAt(aEvent.clientX, aEvent.clientY, row, col, {});
  158.   if (col.value) {
  159.     // restore this specific tab in the same window for middle-clicking
  160.     // or Ctrl+clicking on a tab's title
  161.     if ((aEvent.button == 1 || aEvent.ctrlKey) && col.value.id == "title" &&
  162.         !treeView.isContainer(row.value))
  163.       restoreSingleTab(row.value, aEvent.shiftKey);
  164.     else if (col.value.id == "restore")
  165.       toggleRowChecked(row.value);
  166.   }
  167. }
  168.  
  169. function onListKeyDown(aEvent) {
  170.   switch (aEvent.keyCode)
  171.   {
  172.   case KeyEvent.DOM_VK_SPACE:
  173.     toggleRowChecked(document.getElementById("tabList").currentIndex);
  174.     break;
  175.   case KeyEvent.DOM_VK_RETURN:
  176.     var ix = document.getElementById("tabList").currentIndex;
  177.     if (aEvent.ctrlKey && !treeView.isContainer(ix))
  178.       restoreSingleTab(ix, aEvent.shiftKey);
  179.     break;
  180.   case KeyEvent.DOM_VK_UP:
  181.   case KeyEvent.DOM_VK_DOWN:
  182.   case KeyEvent.DOM_VK_PAGE_UP:
  183.   case KeyEvent.DOM_VK_PAGE_DOWN:
  184.   case KeyEvent.DOM_VK_HOME:
  185.   case KeyEvent.DOM_VK_END:
  186.     aEvent.preventDefault(); // else the page scrolls unwantedly
  187.     break;
  188.   }
  189. }
  190.  
  191. // Helper functions
  192.  
  193. function getBrowserWindow() {
  194.   return window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation)
  195.                .QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem
  196.                .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
  197. }
  198.  
  199. function toggleRowChecked(aIx) {
  200.   var item = gTreeData[aIx];
  201.   item.checked = !item.checked;
  202.   treeView.treeBox.invalidateRow(aIx);
  203.   
  204.   function isChecked(aItem) aItem.checked;
  205.   
  206.   if (treeView.isContainer(aIx)) {
  207.     // (un)check all tabs of this window as well
  208.     for each (var tab in item.tabs) {
  209.       tab.checked = item.checked;
  210.       treeView.treeBox.invalidateRow(gTreeData.indexOf(tab));
  211.     }
  212.   }
  213.   else {
  214.     // update the window's checkmark as well (0 means "partially checked")
  215.     item.parent.checked = item.parent.tabs.every(isChecked) ? true :
  216.                           item.parent.tabs.some(isChecked) ? 0 : false;
  217.     treeView.treeBox.invalidateRow(gTreeData.indexOf(item.parent));
  218.   }
  219.   
  220.   document.getElementById("errorTryAgain").disabled = !gTreeData.some(isChecked);
  221. }
  222.  
  223. function restoreSingleTab(aIx, aShifted) {
  224.   var tabbrowser = getBrowserWindow().gBrowser;
  225.   var newTab = tabbrowser.addTab();
  226.   var item = gTreeData[aIx];
  227.   
  228.   var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
  229.   var tabState = gStateObject.windows[item.parent.ix]
  230.                              .tabs[aIx - gTreeData.indexOf(item.parent) - 1];
  231.   ss.setTabState(newTab, tabState.toSource());
  232.   
  233.   // respect the preference as to whether to select the tab (the Shift key inverses)
  234.   var prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  235.   if (prefBranch.getBoolPref("browser.tabs.loadInBackground") != !aShifted)
  236.     tabbrowser.selectedTab = newTab;
  237. }
  238.  
  239. // Tree controller
  240.  
  241. var treeView = {
  242.   _atoms: {},
  243.   _getAtom: function(aName)
  244.   {
  245.     if (!this._atoms[aName]) {
  246.       var as = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomService);
  247.       this._atoms[aName] = as.getAtom(aName);
  248.     }
  249.     return this._atoms[aName];
  250.   },
  251.  
  252.   treeBox: null,
  253.   selection: null,
  254.  
  255.   get rowCount()                     { return gTreeData.length; },
  256.   setTree: function(treeBox)         { this.treeBox = treeBox; },
  257.   getCellText: function(idx, column) { return gTreeData[idx].label; },
  258.   isContainer: function(idx)         { return "open" in gTreeData[idx]; },
  259.   getCellValue: function(idx, column){ return gTreeData[idx].checked; },
  260.   isContainerOpen: function(idx)     { return gTreeData[idx].open; },
  261.   isContainerEmpty: function(idx)    { return false; },
  262.   isSeparator: function(idx)         { return false; },
  263.   isSorted: function()               { return false; },
  264.   isEditable: function(idx, column)  { return false; },
  265.   getLevel: function(idx)            { return this.isContainer(idx) ? 0 : 1; },
  266.  
  267.   getParentIndex: function(idx) {
  268.     if (!this.isContainer(idx))
  269.       for (var t = idx - 1; t >= 0 ; t--)
  270.         if (this.isContainer(t))
  271.           return t;
  272.     return -1;
  273.   },
  274.  
  275.   hasNextSibling: function(idx, after) {
  276.     var thisLevel = this.getLevel(idx);
  277.     for (var t = after + 1; t < gTreeData.length; t++)
  278.       if (this.getLevel(t) <= thisLevel)
  279.         return this.getLevel(t) == thisLevel;
  280.     return false;
  281.   },
  282.  
  283.   toggleOpenState: function(idx) {
  284.     if (!this.isContainer(idx))
  285.       return;
  286.     var item = gTreeData[idx];
  287.     if (item.open) {
  288.       // remove this window's tab rows from the view
  289.       var thisLevel = this.getLevel(idx);
  290.       for (var t = idx + 1; t < gTreeData.length && this.getLevel(t) > thisLevel; t++);
  291.       var deletecount = t - idx - 1;
  292.       gTreeData.splice(idx + 1, deletecount);
  293.       this.treeBox.rowCountChanged(idx + 1, -deletecount);
  294.     }
  295.     else {
  296.       // add this window's tab rows to the view
  297.       var toinsert = gTreeData[idx].tabs;
  298.       for (var i = 0; i < toinsert.length; i++)
  299.         gTreeData.splice(idx + i + 1, 0, toinsert[i]);
  300.       this.treeBox.rowCountChanged(idx + 1, toinsert.length);
  301.     }
  302.     item.open = !item.open;
  303.     this.treeBox.invalidateRow(idx);
  304.   },
  305.  
  306.   getCellProperties: function(idx, column, prop) {
  307.     if (column.id == "restore" && this.isContainer(idx) && gTreeData[idx].checked === 0)
  308.       prop.AppendElement(this._getAtom("partial"));
  309.     if (column.id == "title")
  310.       prop.AppendElement(this._getAtom(this.getImageSrc(idx, column) ? "icon" : "noicon"));
  311.   },
  312.  
  313.   getRowProperties: function(idx, prop) {
  314.     var winState = gTreeData[idx].parent || gTreeData[idx];
  315.     if (winState.ix % 2 != 0)
  316.       prop.AppendElement(this._getAtom("alternate"));
  317.   },
  318.  
  319.   getImageSrc: function(idx, column) {
  320.     if (column.id == "title")
  321.       return gTreeData[idx].src || null;
  322.     return null;
  323.   },
  324.  
  325.   getProgressMode : function(idx, column) { },
  326.   cycleHeader: function(column) { },
  327.   cycleCell: function(idx, column) { },
  328.   selectionChanged: function() { },
  329.   performAction: function(action) { },
  330.   performActionOnCell: function(action, index, column) { },
  331.   getColumnProperties: function(column, prop) { }
  332. };
  333.